package models;

import org.eclipse.leshan.client.request.ServerIdentity;
import org.eclipse.leshan.client.resource.BaseInstanceEnabler;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.response.ExecuteResponse;
import org.eclipse.leshan.core.response.ReadResponse;
import org.eclipse.leshan.core.response.WriteResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sensors.IWaterMeter;
import sensors.impl.RandomWaterMeter;
import util.Configuration;

import java.util.Arrays;
import java.util.List;

public class WaterMeterSensor extends BaseInstanceEnabler {

    private static final Logger LOG = LoggerFactory.getLogger(WaterMeterSensor.class);

    // Resource Id
    private static final int SENSOR_VALUE = 5700;       // R
    private static final int SENSOR_UNIT = 5701;        // R
    private static final int APPLICATION_TYPE = 5750;   // RW
    private static final int SENSOR_TYPE = 5751;        // R
    private static final int INTERVAL_PERIOD = 6000;    // R
    private static final int INTERVAL_CHANGE = 6010;    // E

    private IWaterMeter waterMeter;
    private String sensorType;
    private String sensorUnit;
    private int intervalPeriodValue;

    @Override
    public synchronized ReadResponse read(ServerIdentity identity, int resourceid) {
        switch (resourceid) {
            case SENSOR_VALUE:
                return ReadResponse.success(resourceid, this.waterMeter.getMeterCount());
            case SENSOR_TYPE:
                return ReadResponse.success(resourceid, this.sensorType);
            case SENSOR_UNIT:
                return ReadResponse.success(resourceid, this.sensorUnit);
            case INTERVAL_PERIOD:
                return ReadResponse.success(resourceid, this.intervalPeriodValue);
            case APPLICATION_TYPE:
                return ReadResponse.success(resourceid, Configuration.applicationType);
            default:
                return super.read(identity, resourceid);
        }
    }

    @Override
    public synchronized WriteResponse write(ServerIdentity identity, int resourceid, LwM2mResource value) {
        switch (resourceid) {
            case APPLICATION_TYPE:
                updateApplicationType(value.getValue().toString());
                return WriteResponse.success();
            default:
                return super.write(identity, resourceid, value);
        }
    }

    @Override
    public synchronized ExecuteResponse execute(ServerIdentity identity, int resourceid, String params) {
        switch (resourceid) {
            case INTERVAL_CHANGE:
                try {
                    int interval = Integer.parseInt(params);
                    updateIntervalPeriod(interval);
                    return ExecuteResponse.success();
                } catch (NumberFormatException e) {
                    LOG.warn("Param does not contain a parsable string");
                    return ExecuteResponse.badRequest("Param does not contain a parsable string");
                }
            default:
                return super.execute(identity, resourceid, params);
        }
    }

    private static final List<Integer> supportedResources = Arrays.asList(
            SENSOR_VALUE,
            SENSOR_UNIT,
            APPLICATION_TYPE,
            SENSOR_TYPE,
            INTERVAL_PERIOD,
            INTERVAL_CHANGE
    );

    public WaterMeterSensor() {
        this.intervalPeriodValue = Configuration.defaultIntervalPeriod;
        this.waterMeter = RandomWaterMeter.getInstance();
        this.sensorType = Configuration.sensorType;
        this.sensorUnit = Configuration.sensorUnit;
    }

    @Override
    public List<Integer> getAvailableResourceIds(ObjectModel model) {
        return supportedResources;
    }

    private void updateApplicationType(String value) {
        Configuration.updateKey("applicationType", value);
    }

    private void updateIntervalPeriod(int value) {
        this.intervalPeriodValue = value;
        Configuration.updateKey("defaultIntervalPeriod", String.valueOf(value));
    }
}
